⓪ ⓪ MODULE PrgLoad; (*$E MAC -> Linker erzeugt ACC-Endung *)⓪ ⓪ (*⓪!* Hinweis/Copyright:⓪!* ------------------⓪!* Die Veröffentlichungsrechte dieses Programms und seiner Quellen liegt⓪!* beim Autor Thomas Tempelmann und der Zeitschrift TOS (ICP-Verlag,⓪!* München-Vaterstetten).⓪!*⓪!* Mit Erwerb der Zeitschrift "TOS" steht es Ihnen frei, das Programm⓪!* zu nutzen. Das Programm ist also keine Freeware oder PD!⓪!* Sie dürfen das Programm verändern, jedoch nicht selbst "verbesserte"⓪!* Versionen dieses Programm verbreiten. Dies obliegt allein dem Urheber,⓪!* also Thomas Tempelmann.⓪!*⓪!* Ich hoffe, Sie beachten diese Hinweise. Ich wäre schwer enttäuscht,⓪!* wenn plötzlich eine Version 2.1, die nicht von mir stammt, auf⓪!* dem PD- oder Raubkopiermarkt erscheint. Dann könnte dies der letzte⓪!* Beitrag von mir gewesen sein. Fairness und Vertrauen sind wichtig⓪!* für das Weiterleben dieser Form der Softwareveröffentlichung!⓪!*⓪!* Für weitere Fragen und Wünsche wenden Sie sich bitte an mich:⓪!* Thomas Tempelmann, Nordendstr. 64, D-8000 München 40.⓪!*⓪!* Über dieses Programm:⓪!* ---------------------⓪!* In der Ausgabe 4/91 der Zeitschrift TOS finden Sie die ausführliche⓪!* Beschreibung dieses nützlichen Programms.⓪!*⓪!* Dieses Modul ist ohne Änderungen nur mit Megamax Modula-2 (System 2.2,⓪!* Compiler 4.0) oder höher übersetzbar. Desweiteren gehören die beiden⓪!* Quellen des Moduls "PrgLoader" (PRGLOADE.D & PRGLOADE.I) zu diesem⓪!* Programm und müssen zuvor übersetzt werden.⓪!*⓪!* Mögliche Verbesserungen:⓪!* ------------------------⓪!* - Überwachen, ob "UsedHeapSize" bei jedem Programmlauf gleich bleibt.⓪!* - Selbstmodifizierenden Code erkennen und dann Warnung anzeigen mit⓪!* Option, das Programm freizugeben.⓪!*⓪!*----------------------------------------------------------------------------⓪!* 22.10.88 TT Grunderstellung ModLoad⓪!* 21.12.88 TT Fertigstellung der Version 1.0 aus ModLoad 1.0⓪!* 20.12.90 TT Fertigstellung der Version 2.0 aus ModLoad 1.3⓪!*----------------------------------------------------------------------------⓪!*)⓪ ⓪ (*$R-,S- Keine Bereichs-, Überlauf- und Stack-Prüfungen erzeugen *)⓪ ⓪ FROM PrgLoader IMPORT⓪"QueryLoaded, LoadProgram, UnLoadProgram, ProgramLoaded, CallProgram,⓪"UsedHeapSize, LoaderResults;⓪ ⓪ FROM SYSTEM IMPORT⓪"ASSEMBLER, CAST, ADDRESS, ADR, TSIZE, BYTE, WORD, LONGWORD;⓪ ⓪ FROM AESWindows IMPORT⓪"UpdateWindow;⓪ ⓪ FROM AESForms IMPORT⓪"FormAlert;⓪ ⓪ FROM AESMisc IMPORT⓪"ShellFind;⓪ ⓪ FROM AESMisc IMPORT⓪"SelectFile;⓪ ⓪ FROM EasyGEM0 IMPORT⓪"WrapAlert;⓪ ⓪ FROM MOSGlobals IMPORT⓪"PathStr, NameStr, FileStr, SfxStr, MemArea;⓪ ⓪ FROM FileNames IMPORT⓪"FileName, PathConc, SplitPath, SplitName;⓪ ⓪ FROM Files IMPORT⓪"File, Open, Close, EOF, State, Access;⓪ ⓪ FROM Text IMPORT⓪"EOL, ReadFromLine, ReadLn;⓪ ⓪ FROM StrConv IMPORT⓪"CardToStr, StrToLCard;⓪ ⓪ FROM GEMEnv IMPORT⓪"InitApplication, ExitApplication;⓪ ⓪ FROM AESEvents IMPORT⓪"MessageEvent, MessageBuffer, accOpen;⓪ ⓪ FROM AESMenus IMPORT⓪"RegisterAcc;⓪ ⓪ FROM PrgCtrl IMPORT⓪"Accessory;⓪ ⓪ FROM MOSCtrl IMPORT⓪"ProcessID (* Zeiger auf den aktuellen GEMDOS-Prozeß *);⓪ ⓪ FROM SysInfo IMPORT⓪"UseStackFrame;⓪ ⓪ FROM Directory IMPORT⓪"GetDefaultPath;⓪ ⓪ IMPORT FuncStrings, Strings, XBRA, BIOS;⓪ ⓪ ⓪ CONST LoaderStackSize = 4000; (* Stackgröße zum Aufruf des Loaders *)⓪ ⓪(Kennung = 'PrgL'; (* XBRA-Kennung für TRAP #1-Handler *)⓪(PrgName = 'PrgLoad'; (* Name dieses Moduls (auch ACC-Eintrag) *)⓪(Version = '2.0'; (* Nicht ändern und veröffentlichen (s.o.)! *)⓪(InfName = 'PRGLOAD.INF';(* Name der INF-Datei *)⓪ ⓪ ⓪ TYPE PtrPexecPar = POINTER TO RECORD⓪5mode: (loadExec, unused1, unused2, load, exec, create);⓪5fileName: ADDRESS;⓪5arg: ADDRESS;⓪5env: ADDRESS⓪3END;⓪ ⓪%PexecRes = RECORD⓪2exitCode: INTEGER;⓪2didExec: BOOLEAN;⓪0END;⓪ ⓪ VAR⓪"DefaultHeap: LONGCARD; (* Heap-Größe, wenn keine andere Angabe *)⓪"DidShowInfo, GotHeapSize, GetHeapSize: BOOLEAN;⓪"Desktop: ADDRESS; (* Prozeßkennung des Desktops, invariabel *)⓪ ⓪"myName: Strings.String;⓪"path: ARRAY [0..127] OF CHAR;⓪"arg: ARRAY [0..128] OF CHAR;⓪ ⓪"entry, at: ADDRESS;⓪"carrier: XBRA.Carrier;⓪"stackhi: ADDRESS;⓪"doingPexec: BOOLEAN;⓪"stackFrameOffs: SHORTCARD;⓪"ok: BOOLEAN;⓪ ⓪ ⓪ PROCEDURE Alert (s: ARRAY OF CHAR);⓪ ⓪"VAR button: CARDINAL;⓪&ok: BOOLEAN;⓪&msg: ARRAY [0..250] OF CHAR;⓪ ⓪"BEGIN⓪$Strings.Assign (s, msg, ok);⓪$(* Meldung mit FormAlert-Dialog anzeigen *)⓪$WrapAlert (msg, 0);⓪$Strings.Insert ('[0][', 0, msg, ok);⓪$Strings.Append ('][ OK ]', msg, ok);⓪$FormAlert (1, msg, button);⓪"END Alert;⓪ ⓪ PROCEDURE doLoadWithMsg (REF name: ARRAY OF CHAR);⓪"VAR result: LoaderResults;⓪"BEGIN⓪$IF ProcessID^ # Desktop THEN⓪&Alert ("Das Laden ist nur vom Desktop aus möglich!")⓪$ELSE⓪&SplitPath (name, path, arg);⓪&LoadProgram (name, DefaultHeap, result);⓪&IF result = noError THEN⓪(Strings.Append (' wurde geladen', arg, ok)⓪&ELSIF result = alreadyLoaded THEN⓪(Strings.Append (' ist bereits geladen', arg, ok)⓪&ELSE⓪(Strings.Append (' kann nicht geladen werden', arg, ok)⓪&END;⓪&Alert (arg)⓪$END;⓪"END doLoadWithMsg;⓪ ⓪ PROCEDURE doUnLoadWithMsg (REF name: ARRAY OF CHAR);⓪"VAR result: LoaderResults;⓪"BEGIN⓪$SplitPath (name, path, arg);⓪$UnLoadProgram (name, result);⓪$IF result = noError THEN⓪&Strings.Append (' wurde freigegeben', arg, ok);⓪$ELSE⓪&Strings.Append (' war nicht geladen', arg, ok)⓪$END;⓪$Alert (arg)⓪"END doUnLoadWithMsg;⓪ ⓪ PROCEDURE hdlPexec (par: PtrPexecPar): PexecRes;⓪"(* Return: TRUE: alte Pexec-Funktion aufrufen, sonst Trap beenden *)⓪ ⓪"PROCEDURE getArg (dosArg: ADDRESS; VAR txt: ARRAY OF CHAR);⓪$(*⓪%* Wandelt Pexec-Argumentzeile in String um⓪%*)⓪$BEGIN⓪&ASSEMBLER⓪(MOVE.L dosArg(A6),A0 ; A0: dosArg⓪(MOVE.L txt(A6),A1 ; A1: ADR (txt)⓪(CLR D0⓪(MOVE.B (A0)+,D0 ; Länge der Arg-Zeile⓪(BRA c⓪&l MOVE.B (A0)+,(A1)+ ; Zeile kopieren⓪&c DBRA D0,l⓪(CLR.B (A1) ; String-Ende mit 0C abschließen⓪&END⓪$END getArg;⓪ ⓪"VAR fn: POINTER TO FileStr;⓪&sfx: SfxStr;⓪&exitCode: LONGINT;⓪&result: LoaderResults;⓪&res: PexecRes;⓪&ok: BOOLEAN;⓪ ⓪"BEGIN (* hdlPexec *)⓪$res.didExec:= FALSE;⓪$res.exitCode:= 0;⓪$fn:= par^.fileName;⓪$IF par^.mode = loadExec (*trifft immer zu, da schon vorher geprüft*) THEN⓪&IF (ProcessID^ = Desktop) & (BIOS.ControlKey IN BIOS.GetKBShift ()) THEN⓪((* Das Laden ist nur vom Desktop aus erlaubt! *)⓪(IF BIOS.LeftShift IN BIOS.GetKBShift () THEN⓪*doUnLoadWithMsg (fn^)⓪(ELSE⓪*doLoadWithMsg (fn^)⓪(END;⓪(res.didExec:= TRUE⓪&ELSE⓪(IF GetHeapSize OR ProgramLoaded (fn^) THEN⓪*(* hier normalerweise nur geladene Programme starten; nicht⓪+* geladene Programme "normal" über GEMDOS starten lassen⓪+* (s. 'hdlGemdos') *)⓪*getArg (par^.arg, arg);⓪*GotHeapSize:= TRUE;⓪*CallProgram (fn^, arg, par^.env, exitCode);⓪*res.exitCode:= SHORT (exitCode);⓪*res.didExec:= TRUE⓪(END⓪&END;⓪$END;⓪$RETURN res⓪"END hdlPexec;⓪ ⓪ VAR regStack: ARRAY [1..256] OF WORD; (* Stack für Register-Sicherung *)⓪ ⓪ PROCEDURE hdlGemdos;⓪"(*$L-*)⓪"BEGIN⓪$ASSEMBLER⓪(BTST.B #5,(A7) ; War Supervisormode aktiv ?⓪(BNE.B super ; Ja, dann stehen Arg. auf SSP⓪(MOVE.L USP,A0⓪(CMPI.W #$4B,(A0) ; Pexec - Funktion ?⓪(BEQ.B hdlPexecUser⓪ dos ; normale GEMDOS-Funktion ausführen⓪(MOVE.L entry,A0⓪(MOVE.L -4(A0),A0⓪(JMP (A0)⓪ super MOVE.W stackFrameOffs,D0⓪(CMPI.W #$4B,6(A7,D0.W) ; Pexec - Funktion ?⓪(BNE.B dos ; Nein -> GEMDOS aufrufen⓪(LEA 6(A7,D0.W),A0 ; Basis d. Argumente nach A0⓪ hdlPexecUser:⓪(TST.W doingPexec ; ist dies der "Pexec" von "CallModule"?⓪(BEQ noPexec ; nein -> dann werten wir ihn selbst aus.⓪ ⓪(CLR.W doingPexec⓪(BRA dos ; ja -> dann lassen wir ihn zum GEMDOS durch⓪ ⓪ noPexec ; prüfen, ob Prg gestartet & ausgeführt werden soll.⓪(ADDQ.L #2,A0⓪(CMPI #loadExec,PtrPexecPar.mode(A0)⓪(BNE dos⓪ ⓪(MOVE.L stackhi,A1 ; neuen SP f. Modula-Funktionen laden⓪(; Register auf regStack retten:⓪(MOVEM.L D1-D7/A2-A6,-(A1)⓪(MOVE.W (A7)+,-(A1) ; SR vom SSP retten⓪(MOVE.L (A7)+,-(A1) ; PC vom SSP retten⓪(TST.W stackFrameOffs ; StackFrame vorhanden?⓪(BEQ noSF1 ; nein⓪(MOVE.W (A7)+,-(A1) ; StackFrame vom SSP retten⓪ noSF1: MOVE.L USP,A2⓪(MOVE.L A2,-(A1) ; USP retten⓪(MOVE.L A7,-(A1) ; SSP retten⓪(MOVE.L A1,stackhi⓪(MOVE.L A1,USP ; den regStack auch für Malloc-Aufruf nutzen⓪(ANDI #$CFFF,SR ; User Mode aktivieren⓪ ⓪(; Stack f. Modula-Funktionen (Loader-Aufruf) reservieren⓪(MOVE.L A0,-(A7)⓪(MOVE.L #LoaderStackSize,-(A7)⓪(MOVE #$48,-(A7) ; Malloc()⓪(TRAP #1⓪(ADDQ.L #6,A7⓪(MOVE.L (A7)+,A0⓪(MOVE.L D0,A3⓪(LEA LoaderStackSize(A3),A7⓪ ⓪(MOVE #1,doingPexec⓪(MOVE.L A0,(A3)+⓪(JSR hdlPexec ; Pexec-Sonderbehandlung⓪(CLR.W doingPexec⓪(MOVE.L -(A3),D0 ; Pexec - Rückgabewert⓪ ⓪(; Modula-Stack wieder freigeben⓪(MOVE.L stackhi,A7 ; regStack wieder für SP verwenden⓪(MOVE.L D0,-(A7)⓪(MOVE.L A3,-(A7)⓪(MOVE #$49,-(A7) ; Mfree()⓪(TRAP #1⓪(ADDQ.L #6,A7⓪(⓪(; zurück in den Supervisor-Mode:⓪(CLR.L -(A7)⓪(MOVE #$20,-(A7)⓪(TRAP #1⓪(ADDQ.L #6,A7⓪(MOVE.L (A7)+,D0⓪(⓪(MOVE.L A7,A1⓪(MOVE.L (A1)+,A7 ; SSP zurück⓪(MOVE.L (A1)+,A0 ; USP zurück⓪(MOVE.L A0,USP⓪(TST.W stackFrameOffs ; StackFrame vorhanden?⓪(BEQ noSF2 ; nein⓪(MOVE.W (A1)+,-(A7) ; StackFrame zurück⓪ noSF2: MOVE.L (A1)+,-(A7) ; PC zurück⓪(MOVE.W (A1)+,-(A7) ; SR zurück⓪(MOVEM.L (A1)+,D1-D7/A2-A6⓪(MOVE.L A1,stackhi⓪ ⓪(TST.W D0⓪(BEQ dos ; Wurde nicht ausgeführt -> GEMDOS aufrufen⓪(⓪(SWAP D0 ; Exitcode liefern⓪(EXT.L D0⓪(RTE⓪$END⓪"END hdlGemdos;⓪"(*$L=*)⓪ ⓪ PROCEDURE readInfFile;⓪"(*⓪#* Liest die Datei "MODLOAD.INF" und lädt die darin angegebenen Module.⓪#*)⓪"⓪"VAR f: File;⓪&s, s2: Strings.String;⓪&heapValid: BOOLEAN;⓪&pos: CARDINAL;⓪&heap: LONGCARD;⓪&result: LoaderResults;⓪"⓪"BEGIN⓪$s:= InfName;⓪$ShellFind (s);⓪$Open (f, s, readSeqTxt);⓪$WHILE NOT EOF (f) DO⓪&ReadFromLine (f, s); (* Programmnamen einlesen *)⓪&ReadLn (f); (* Zeilenende überlesen *)⓪&Strings.Split (s, Strings.PosLen (' ', s, 0), s, s2, ok);⓪&Strings.Upper (s);⓪&pos:= 0;⓪&heap:= StrToLCard (s2, pos, heapValid);⓪&IF Strings.StrEqual (s, "HEAP") THEN⓪(IF heapValid THEN DefaultHeap:= heap END⓪&ELSE⓪(IF NOT heapValid THEN heap:= DefaultHeap END;⓪(LoadProgram (s, heap, result) (* Programm laden *)⓪&END⓪$END;⓪$Close (f);⓪"END readInfFile;⓪ ⓪ PROCEDURE service;⓪ ⓪"VAR defbut, button: CARDINAL;⓪&s: ARRAY [0..199] OF CHAR;⓪&name: NameStr;⓪&didShow, ok: BOOLEAN;⓪ ⓪"PROCEDURE showPrg (REF name: ARRAY OF CHAR; heapSize: LONGCARD;⓪5noOfRuns: CARDINAL): BOOLEAN;⓪$BEGIN⓪&s:= "[0][ |";⓪&Strings.Append (FileName (name), s, ok);⓪&Strings.Append (" | |", s, ok);⓪&IF noOfRuns > 0 THEN⓪(Strings.Append ("Benutzte Heap-Größe: ", s, ok);⓪(Strings.Append (CardToStr (heapSize, 0), s, ok);⓪&ELSE⓪(Strings.Append ("Wurde noch nicht gestartet", s, ok)⓪&END;⓪&Strings.Append (" | ][Weiter|Freigeben|Abbruch]", s, ok);⓪&FormAlert (1, s, button);⓪&IF button = 2 THEN⓪(doUnLoadWithMsg (name)⓪&END;⓪&didShow:= TRUE;⓪&RETURN button # 3⓪$END showPrg;⓪ ⓪"BEGIN⓪$IF GetHeapSize THEN⓪&GetHeapSize:= FALSE;⓪&IF NOT GotHeapSize THEN⓪(Alert ('Sie haben doch noch kein Programm gestartet, oder?')⓪&ELSIF UsedHeapSize = MAX (LONGCARD) THEN⓪(Alert ('Das Programm scheint allen verfügbaren Speicher zu belegen')⓪&ELSIF UsedHeapSize = 0 THEN⓪(Alert ('Das Programm belegt keinen zusätzlichen Heap (Größe ist 0)')⓪&ELSE⓪(s:= 'Die belegte Heap-Größe ist:';⓪(Strings.Append (CardToStr (UsedHeapSize,0), s, ok);⓪(Alert (s)⓪&END⓪$END;⓪$defbut:= 1;⓪$LOOP⓪&s:= "[0][ PrgLoad "+Version+"|"⓪-+" |"⓪-+"Erstellt von Thomas Tempelmann |"⓪-+" mit Megamax Modula-2|"⓪-+" für das TOS-Magazin (4/91)]"⓪-+"[Mehr...|Info|Ausgang]";⓪&IF NOT DidShowInfo THEN⓪(defbut:= 2⓪&END;⓪&FormAlert (defbut, s, button);⓪&IF button = 3 THEN⓪(EXIT⓪&ELSIF button = 2 THEN⓪(FormAlert (1, "[0][Autor: | Thomas Tempelmann |"⓪3+" Nordendstraße 64| D-8000 München 40| West Germany]"⓪3+"[ OK ]", button);⓪(Alert ("Ausführliche Informationen zu diesem Programm finden Sie "⓪.+"im TOS-Magazin Ausgabe 4/91.");⓪(DidShowInfo:= TRUE⓪&ELSE (* button = 1 *)⓪(s:= "[0][ |Wählen Sie:| Geladene Programme zeigen |"⓪,+" Heap-Größe ermitteln/setzen| ";⓪(IF ProcessID^ = Desktop THEN⓪*(* Das Laden ist nur vom Desktop aus erlaubt! *)⓪*Strings.Append ("Programm laden", s, ok)⓪(END;⓪(Strings.Append ("][ Zeige | Heap ", s, ok);⓪(IF ProcessID^ = Desktop THEN⓪*Strings.Append ("| Lade ", s, ok)⓪(END;⓪(Strings.Append ("]", s, ok);⓪(FormAlert (1, s, button);⓪(IF button = 3 THEN⓪*name:= '';⓪*GetDefaultPath (path);⓪*SelectFile (path, name, ok);⓪*IF ok & (name[0] # '') THEN⓪,doLoadWithMsg (PathConc (path, name));⓪*END⓪(ELSIF button = 1 THEN⓪*didShow:= FALSE;⓪*QueryLoaded (showPrg);⓪*IF NOT didShow THEN⓪,Alert ("Es ist kein Programm geladen")⓪*END⓪(ELSE⓪*FormAlert (1, "[0][ |Wählen Sie:|"⓪=+" Benutzte Heap-Größe eines |"⓪=+" Programm ermitteln|"⓪=+" Heap-Größe setzen| ]"⓪=+"[Ermitteln|Setzen]", button);⓪*IF button = 1 THEN⓪,Alert ("Starten Sie ein Programm und kehren Sie dann zurück");⓪,GotHeapSize:= FALSE;⓪,GetHeapSize:= TRUE;⓪,RETURN⓪*ELSE⓪,LOOP⓪.s:= "[0][Voreingestellte Heap-Größe|"⓪1+"zum Laden eines Programms: | |";⓪.Strings.Append (CardToStr (DefaultHeap, 15), s, ok);⓪.Strings.Append ("| ][Mehr|Weniger|OK]", s, ok);⓪.FormAlert (3, s, button);⓪.IF button = 1 THEN⓪0DefaultHeap:= DefaultHeap + DefaultHeap DIV 2⓪.ELSIF button = 2 THEN⓪0DefaultHeap:= DefaultHeap - DefaultHeap DIV 3⓪.ELSE⓪0EXIT⓪.END⓪,END⓪*END⓪(END⓪&END;⓪&defbut:= 3⓪$END (* LOOP *)⓪"END service;⓪ ⓪ VAR msg: MessageBuffer;⓪$menuID: CARDINAL;⓪$button: CARDINAL;⓪ ⓪ BEGIN⓪"InitApplication (ok);⓪"IF NOT Accessory () THEN⓪$Alert ('PrgLoad läuft nur als Accessory!')⓪"ELSE⓪$doingPexec:= FALSE;⓪$DefaultHeap:= 8192; (* Heap-Größe, wenn keine andere Angabe *)⓪$GetHeapSize:= FALSE;⓪$DidShowInfo:= FALSE;⓪$IF UseStackFrame () THEN stackFrameOffs:= 2 ELSE stackFrameOffs:= 0 END;⓪$Desktop:= ProcessID^;⓪$(* 'hdlGemdos' in TRAP #1 einhängen *)⓪$IF NOT XBRA.Installed (Kennung, $84 (* GEMDOS/TRAP#1 *), at) THEN⓪&XBRA.Create (carrier, Kennung, CAST (ADDRESS, hdlGemdos), entry);⓪&XBRA.Install (entry, at);⓪&stackhi:= ADR (regStack) + SIZE (regStack);⓪&myName:= PrgName;⓪&Strings.Insert (' ', 0, myName, ok);⓪&RegisterAcc (ADR (myName), menuID , ok);⓪&UpdateWindow (TRUE);⓪&readInfFile;⓪&UpdateWindow (FALSE);⓪&LOOP⓪(MessageEvent (msg);⓪(IF (msg.msgType = accOpen) THEN⓪*service⓪(END⓪&END⓪$END⓪"END⓪ END PrgLoad.⓪ ə